CLR (Сборка + ссылочные-значимые типы)

Сборка и компиляция

Каждый класс/файл представляет из себя отдельный управляемый модуль, модуль включает в себя IL код и метаданные.

Метаданные содержат инфу о типах используемых внутри.

Программа может быть представлена несколькими сборками, каждая сборка в конечном итоге станет либо exe либо dll. Как разделять на сборки выбирает сам разработчик.

Программы написанные под dotnet в теории должны одинокого хорошо запускаться на всех процессорах. Однако, пользователь может указать конкретную платформу, если захочет.

Ngen.exe - утила которая позволяет скомпилировать IL код и поместить в кэш CLR
Это позволит упростить работу для джид

FCL - набор сборок в формате DLL, в него входят разные System. (System.IO, System.Thread)

Управляемый код обеспечивает то, что программа не будет трогать те области памяти, где у нее нет доступа, в некоторых случай, например в Microsoft Server или IIL это позволит работать нескольким программам в рамках одного адресного пространства процесса.

CTS - спецификация типов в рамках CLR

Команда с обращение к компилятору csc.exe (В целом можно убрать все параметры, т.к. они такие по умолчанию)

C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /out:Program.exe /t:exe /r:MSCorLib.dll Program.cs

MSCorLib.dll - файл в котором лежат основные типы C# байт, стринг, чар, инт итд

Можно создать файл параметров, и передавать его
или хранить его в локальной директории
Или изменит глобальный в директории с csc

Сборка может быть представлена как одним файлом, так и несколькими, это полезно например для погрузки типов, чтобы читать не полностью. Студия поддерживает только однофайловые сборки, но можно из командной строки сделать много файловую. Тогда сборка будет представлена манифестом внутри одного из файлов, который будет хранить инфу о других файлах.

Через атрибуты сборки можно настраивать поля во вкладке Details, когда dll открываешь правой кнопкой мыши.

Это все долнжо вноситься в файл AssemblyInfo.cs

Переполнения.

По умолчанию компилятору шарпа пофиг на переполнения, но это можно изменить параметрами компилятора, чтобы он генерил оверфлоуЕксепшн. Также существуют ключевые слова чеккет и анчеккет, которые заставляют генерить IL код операторы с проверкой переполнения. Также, т.к. вся проверка заключается в операторах ил-кода включающий проверку, например add.ovf , эти операторы не будут работать на Decimal и BigInteger, так как в IL коде они представлены типами, а не примитивами.

Ссылочные и значимые типы.

В C# можно атрибутами говорить CLR как располагать поля в памяти
Можно попросить распределять автоматически, как ему лучше. Можно попросить в порядке определения. А можно прям пописывать байты, в какие вписывать, начиная от начала типа. Благодаря этому, можно сделать класс в котором два поля будут записаны на одном месте в памяти, это аналог юнион из плюсов.

Выделение памяти в структуре происходит на этапе

SomeClass variable;

И в этот момент все поля занулены.

То есть “new” не обязательно. Но в случае попытки прочитать поля, которые не были явно проинициализированы, получишь некомпил.
Но можно делать так.

varible.x = 1; 

Все значимые типы унаследованы от ValueType, а он уже от object.

Упаковка-распаковка

Во время упаковки, компилятор копирует значимый объект в кучу и добавляет рядом два значения, ссылку на (объект типа хз что это) и блок синхронизации. И получает ссылку на этот объект из кучи. Далее работает с ним, как с ссылочным типом. Переменную значимого типа можно переиспользовать, т.к. её значения были просто скопированы.

Пример:

StructPoint t;
var list = new ArrayList();
list.Add(t)
// Примечание, ArrayList это старый аналог List, отличие в том, 
// +что он не обобщенный, метод Add() принимает просто object

В этот момент произошла упаковка, значение было скопировано в кучу, а значит с оставшаяся переменная может быть переиспользована.

Обобщения помогают избегать лишней упаковки

Для вызова методов определенных в object требуется упаковка.

По идее, в C# нельзя изменять поля внутри упакованной переменной. Так как упакованная переменная типа object. Однако, можно отнаследовать структуру от интерфеса. Тогда после упаковки можно преобразовать object к интерфейсу и вызывать метод описанный в интерфейсе, например для изменения состояния.
НО Рихтер не рекомендует этим все м заниматься, т.к. это не читаемо, и просит делать поля структур readonly, так все основные, примитивы уже ридонли.

Nullable типы

C# Предоставляет структуру Nullable которая также принимает значимые типы. Реализация простая, там просто флаг HasValue(его можно вызывать) указывающий null ли это и действующий по разному в зависимости от этого флага. Эта структура не может принимать ссылочные типы, тк они и так могут быть налл, но полный аналог в виде T? уже может поддерживать ссылочные типы. Поддержка в виде сахара, т.к. оно не приводит к типу Nullable, а просто во время разработки указывает на то что оно может быть наллом.

CLR поддерживает Nullable из коробки. Это реализуется через упаковки и распаковки:

В случае если метод ожидает тип object, в IL происходит упаковка, но с условием если значение не null. Если null, то просто передается null.

Распаковка действует аналогично.

При вызове GetType() от Nullable возвращается тип T, а не Nullable

Сахар: Nullable можно приводить к интерфейсам, которые реализует T. Это нужно чтобы самому касты не писать.